(function(_global) {
  'use strict';

  var topologyTools = {
    recursionGraphNodeData: recursionGraphNodeData
  };

  function recursionGraphNodeData(options) {
    options = options || {};

    options.data = options.data || [];
    options.dataId = options.dataId || 'id';
    options.dataSId = options.dataSId || 'sId';
    options.dataPId = options.dataPId || 'pId';
    options.dataTitle = options.dataTitle || 'title';
    options.dataText = options.dataText || 'text';

    options.style.node.bgColor = options.style.node.bgColor || '#a5b9cc';
    options.style.node.textColor = options.style.node.textColor || '#fff';
    options.style.node.width = options.style.node.width || 120;
    options.style.node.height = options.style.node.height || 25;

    options.style.drawingBoard.width = options.style.drawingBoard.width || 600;

    return recursionGraphNodeList(options);
  }

  function recursionGraphNodeList(options, level, pNode) {
    var dataList = options.data;
    level = level || 0;
    options.nodeList = options.nodeList || [];

    var currentNodeList = [];
    if (!pNode) {
      pNode = _.find(dataList, function(data) {
        return !data[options.dataPId];
      });
      currentNodeList = [pNode];
    } else {
      currentNodeList = _.filter(dataList, function(data) {
        return data[options.dataPId] == pNode[options.dataId];
      });
    }


    if (currentNodeList) {
      _.forEach(currentNodeList, function(data, index, currentNodeList) {
        if (!_.find(options.nodeList, { name: data[options.dataText] })) {
          generateGraphNode(data, index, currentNodeList, pNode[options.dataId], data[options.dataSId], level, options);
          recursionGraphNodeList(options, level + 1, data);
        }
      });
    }
    return options.nodeList;
  }

  function generateGraphNode(data, index, currentNodeList, pNodeId, sNodeId, level, options) {
    var startX = (options.style.drawingBoard.width - options.style.node.width * currentNodeList.length - 20 * (currentNodeList.length - 1)) / 2;

    var bgColor = options.style.node.bgColor;
    var textColor = options.style.node.textColor;

    if (options.group) {
      _.forEach(options.group, function(item) {
        if (data[item.mark] == item.value) {
          bgColor = item.style.node.bgColor;
          textColor = item.style.node.textColor;
        }
      })
    }

    options.nodeList.push({
      nodeId: data[options.dataId],
      nodeData: data,
      nodeType: data.nodeType,
      x: startX + (options.style.node.width + 20) * index,
      y: level * (options.style.node.height * 2),
      width: options.style.node.width,
      height: options.style.node.height,
      text: {
        value: _.isFunction(options.dataText) ? options.dataText(data) : data[options.dataText],
        title: _.isFunction(options.dataTitle) ? options.dataTitle(data) : data[options.dataTitle],
        color: textColor,
        hover: {
          color: textColor
        }
      },
      bg: {
        color: bgColor,
        hover: {
          color: bgColor
        }
      },
      sourceNodeIds: [pNodeId],
      targetNodeIds: [sNodeId]
    });
  }

  _global.topologyTools = topologyTools;
})(window);